home *** CD-ROM | disk | FTP | other *** search
- #include "stdafx.h"
-
- cSurface::cSurface(int _x, int _y, int _w, int _h, int _total_h, int _edge, int _transparent, int _usescreen, int _dirty_block)
- {
- // Dimensions
-
- screen_x = _x;
- screen_y = _y;
- w = _w;
- h = _h;
-
- // Parameters
-
- total_h = _total_h;
- edge = _edge;
- transparent = _transparent;
- usescreen = _usescreen && !no_blit_hardware && hardware_blit_caps;
-
- // Dirty
-
- dirty_block = _dirty_block;
- dirty_w = w / dirty_block;
- dirty_h = h / dirty_block;
- dirty = new char [dirty_w * dirty_h];
-
- ASSERT(w % dirty_block == 0 && h % dirty_block == 0);
-
- // Reset start and dirty
-
- reset();
-
- // Make surface
-
- if (!usescreen)
- {
- // A separate buffer is used which must be blit into the backbuffer
-
- offset_x = 0, offset_y = 0;
-
- dds = create_surface(w, h, no_blit_hardware || !hardware_blit_caps? DDSCAPS_SYSTEMMEMORY:0, transparent? DDSD_CKSRCBLT:0);
-
- if (dds == 0)
- error("Unable to create game surface");
-
- scroll_src_dds = dds;
- }
- else
- {
- // The backbuffer of the screen is directly used,
- // which is faster but not possible for parallax scrolling
-
- offset_x = screen_x, offset_y = screen_y;
-
- dds = backbuffer;
-
- scroll_src_dds = inawin? backbuffer:screen;
- }
-
- // Get caps
-
- if (FAILED(dds->GetCaps(&caps)))
- error("Unable to get capabilities for surface");
- }
-
- cSurface::~cSurface()
- {
- if (!usescreen)
- dds->Release();
-
- safe_delete(&dirty);
- }
-
- void cSurface::clear_backbuffer(int color)
- {
- // Setup effect for blit
-
- DDBLTFX ddbltfx;
-
- ddbltfx.dwSize = sizeof(ddbltfx);
- ddbltfx.dwFillColor = color;
-
- // Do clear
-
- CRect r(screen_x, screen_y, screen_x + w, screen_y + h);
- while (!draw_ok(backbuffer->Blt(&r, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx)));
- }
-
- void cSurface::blit_to_backbuffer()
- {
- if (!usescreen)
- {
- // Setup rectangle for blit
-
- CRect r(0, 0, w, h);
-
- // Do blit
-
- while (!draw_ok(backbuffer->BltFast(screen_x, screen_y, dds, &r, DDBLTFAST_WAIT | (transparent? DDBLTFAST_SRCCOLORKEY:DDBLTFAST_NOCOLORKEY))));
- }
- }
-
- int cSurface::convert_area(int &x1, int &y1, int &x2, int &y2)
- {
- // Convert to surface coordinates
-
- y1 = start + h - 1 - y1;
- y2 = start + h - 1 - y2;
-
- // Clip
-
- limit_lowerbound(x1, 0);
- limit_upperbound(x2, w - 1);
- limit_lowerbound(y1, 0);
- limit_upperbound(y2, h - 1);
-
- // Check if anything is on screen
-
- if (x1 > x2 || y1 > y2)
- return FALSE;
-
- // Compute results
-
- x1 /= dirty_block;
- y1 /= dirty_block;
- x2 /= dirty_block;
- y2 /= dirty_block;
-
- // Return computation succeeded
-
- return TRUE;
- }
-
- void cSurface::reset()
- {
- // Reset start
-
- last_start = 0;
- start = 0;
-
- // Reset dirty
-
- reset_dirty();
- }
-
- void cSurface::reset_dirty()
- {
- // Make everything not dirty
-
- FillMemory(dirty, dirty_w * dirty_h, FALSE);
- }
-
- void cSurface::all_dirty()
- {
- // Make everything dirty
-
- FillMemory(dirty, dirty_w * dirty_h, TRUE);
- }
-
- void cSurface::add_dirty(int x1, int y1, int x2, int y2)
- {
- // Get area to set
-
- if (!convert_area(x1, y1, x2, y2))
- return;
-
- // Set area dirty
-
- char *d = dirty + x1 + y1 * dirty_w;
-
- for (; y1 <= y2; y1++, d += dirty_w)
- FillMemory(d, x2 - x1 + 1, TRUE);
- }
-
- void cSurface::all_surfaces_dirty()
- {
- game_surface->all_dirty();
-
- if (!no_parallax)
- back_surface->all_dirty();
-
- left_surface->all_dirty();
- right_surface->all_dirty();
- }
-
- void cSurface::all_surfaces_not_dirty()
- {
- game_surface->reset_dirty();
-
- if (!no_parallax)
- back_surface->reset_dirty();
-
- left_surface->reset_dirty();
- right_surface->reset_dirty();
- }
-
- void cSurface::do_scroll()
- {
- // Get scroll difference
-
- int delta = start - last_start;
-
- // Remember new start
-
- last_start = start;
-
- // Scroll difference up or down
-
- if (delta > 0)
- {
- // Scroll up
-
- if (delta < h)
- {
- // Scroll
-
- CRect r(offset_x, offset_y, offset_x + w, offset_y + h - delta);
- while (!draw_ok(dds->BltFast(offset_x, offset_y + delta, scroll_src_dds, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
-
- // Make area dirty
-
- add_dirty(0, start + h - 1, w - 1, start + h - delta);
- }
- else
- {
- // Everything is dirty
-
- all_dirty();
- }
- }
- else if (delta < 0)
- {
- // Scroll down
-
- if (delta > -h)
- {
- // Scroll
-
- CRect r(offset_x, offset_y - delta, offset_x + w, offset_y + h);
- while (!draw_ok(dds->BltFast(offset_x, offset_y, scroll_src_dds, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
-
- // Make area dirty
-
- add_dirty(0, start - delta, w - 1, start);
- }
- else
- {
- // Everything is dirty
-
- all_dirty();
- }
- }
- else if (scroll_src_dds != dds)
- {
- // Copy screen to backbuffer
-
- CRect r(offset_x, offset_y, offset_x + w, offset_y + h);
- while (!draw_ok(dds->BltFast(offset_x, offset_y, scroll_src_dds, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
- }
- }
-
- void cSurface::clear(int color)
- {
- // Setup effect for blit
-
- DDBLTFX ddbltfx;
-
- ddbltfx.dwSize = sizeof(ddbltfx);
- ddbltfx.dwFillColor = color;
-
- // Clear
-
- CRect r(0, 0, w, h);
- while (!draw_ok(dds->Blt(&r, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx)));
- }
-
- void cSurface::clear_dirty(int color)
- {
- // Set blit effects structure
-
- DDBLTFX ddbltfx;
-
- ddbltfx.dwSize = sizeof(ddbltfx);
- ddbltfx.dwFillColor = color;
-
- // Check dirty areas and clear them
-
- char *d = dirty;
-
- for (int y = 0; y < h; y += dirty_block)
- for (int x = 0; x < w; x += dirty_block, d++)
- if (*d)
- {
- CRect r(x, y, x + dirty_block, y + dirty_block);
- while (!draw_ok(dds->Blt(&r, 0, 0, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx)));
- }
- }
-
- void cSurface::write_tiled(cBMP *bmp)
- {
- // tilestart is the start of the tile
-
- int tilestart = start + h - ((start + h) / bmp->h + 1) * bmp->h;
-
- // Get best pointer to dd surface
-
- LPDIRECTDRAWSURFACE4 best = bmp->bestptr(this);
-
- // Check dirty areas and clear them
-
- char *d = dirty;
-
- for (int y = 0; y < h; y += dirty_block)
- for (int x = 0; x < w; x += dirty_block, d++)
- if (*d)
- {
- // Get source range in image
-
- int y1 = (y - tilestart) % bmp->h,
- y2 = (y - tilestart + dirty_block - 1) % bmp->h;
-
- // Write the background
-
- CRect r(x, y1, x + dirty_block, y2 > y1? y2 + 1: bmp->h);
- while (!draw_ok(dds->BltFast(offset_x + x, offset_y + y, best, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
-
- // Check if there's a second part and write it
-
- if (y1 > y2)
- {
- CRect r(x, 0, x + dirty_block, y2 + 1);
- while (!draw_ok(dds->BltFast(offset_x + x, offset_y + y + bmp->h - y1, best, &r, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)));
- }
- }
- }
-
- void cSurface::write_displayable(cDisplayable *l)
- {
- for (; l != 0; l = (cDisplayable *)l->next)
- {
- // Get area occupied by this displayable
-
- int x1 = l->x1, y1 = l->y1, x2 = l->x2, y2 = l->y2;
-
- if (!convert_area(x1, y1, x2, y2))
- continue;
-
- // Write dirty blocks, writing as much as possible in horizontal direction
-
- for (; y1 <= y2; y1++)
- {
- char *d = dirty + x1 + y1 * dirty_w;
-
- int y_game = start + h - 1 - y1 * dirty_block;
-
- for (int x = x1; x <= x2; x++, d++)
- if (*d)
- {
- // Remember first block to write
-
- int x_start = x * dirty_block;
-
- // Get last block to write
-
- for (x++, d++; x <= x2 && *d; x++, d++);
-
- // Write horizontal line of blocks
-
- l->write(x_start, y_game, x * dirty_block - 1, y_game - dirty_block + 1);
- }
- }
- }
- }
-